package spitfire.ksim.algorithm;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Map.Entry;

/**
 * An implementation of {@link LazyClassificationAlgorithm}.
 * It sum up highest K similarity scores of each semantic description, and pick
 * the semantic description with the highest sum value as the final description,
 * and return the highest sum value as similarity.
 *  
 * @author Adam
 */
public class SumTopK implements LazyClassificationAlgorithm {
	private final int k;
	private Double sumSimilarity;
	private Map<String, PriorityQueue<Pair>> sdPrioQMap = new HashMap<String, PriorityQueue<Pair>>();
	
	public SumTopK(int k) {
		if (k < 1) {
			throw new RuntimeException("K can't be < 1");
		}
		this.k = k;
	}
	
	private void doClear() {
		sumSimilarity = null;
		sdPrioQMap.clear();
	}
	
	/* (non-Javadoc)
	 * @see spitfire.ksim.algorithm.LazyClassificationAlgorithm#classifySD(java.util.List, java.util.List)
	 */
	@Override
	public String classifySD(List<Long> timeStampList, List<Double> dataList, List<FuzzyEntry> entryList) {
		doClear();
		// Find the K entries with highest score for each SD
		for (FuzzyEntry entry : entryList) {
			double sc = SimilarityAlgorithm.calculateScore(dataList, entry.getRule());
			System.out.println("Score to " + entry.getSd() + " | "
					+ entry.getNodeId() + ":" + entry.getSensorType() + ": "
					+ sc);
			if (sc > 0) {
				PriorityQueue<Pair> prioQueue = null;
				if (sdPrioQMap.containsKey(entry.getSd())) {
					prioQueue = sdPrioQMap.get(entry.getSd());
				} else {
					prioQueue = new PriorityQueue<Pair>(k + 1);
					sdPrioQMap.put(entry.getSd(), prioQueue);
				}
				prioQueue.offer(new Pair(sc, entry));
				if (prioQueue.size() > k) {
					prioQueue.poll();
				}
			}
		}
		
		String maxSd = null;
		double maxSc = 0;
		// Find highest score and corresponding SD in all SDs
		for (Entry<String, PriorityQueue<Pair>> entry : sdPrioQMap.entrySet()) {
			String sd = entry.getKey();
			PriorityQueue<Pair> prioQ = entry.getValue();
			// Sum up TOP K scores
			double sumSc = 0;
			for (Pair pair : prioQ) {
				sumSc += pair.score;
			}
			
			if (sumSc > maxSc) {
				maxSc = sumSc;
				maxSd = sd;
			}
		}
		sumSimilarity = maxSc;
		return maxSd;
	}
	
	/* (non-Javadoc)
	 * @see spitfire.ksim.algorithm.LazyClassificationAlgorithm#getSimilarity()
	 */
	@Override
	public double getSimilarity() {
		if (sumSimilarity == null) {
			throw new RuntimeException("Invoke classifySD() first");
		}
		return sumSimilarity;
	}
}
